﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Query;
using Microsoft.Xrm.Sdk.Messages;
using Xrm.Framework.Test.Integration;
using Xrm.Solutions.FrameworkSample.Common.Entities;


namespace Xrm.Solutions.FrameworkSample.XrmIntegrationTests.WFActivities
{
    [TestClass]
    public class TestUpdateAccountValueWorkflow : WFActivityIntegrationTest
    {
        #region Properties

        protected override string AsyncOperationName
        {
            get
            {
                return "Update Account Value";
            }
        }

        #endregion

        #region Instance Variables

        private Account account;
        private List<Opportunity> accountOpportunities;

        #endregion

        #region Setup


        protected override Guid SetupPrimaryEntity()
        {
            CrmHelpers.SetConfigurationSetting(this.OrganizationService, "AutoNumberPrefix", "Test" + DateTime.Now);

            account = new Account();
            account.Name = "TestUpdateAccountValueWorkflow " + DateTime.Now;
            account.Id = this.OrganizationService.Create(account);

            Opportunity opportunity1 = new Opportunity();
            opportunity1.Name = "TestUpdateAccountValueWorkflow 1 " + DateTime.Now;
            opportunity1.ActualValue = new Money(800000);
            opportunity1.ParentAccountId = account.ToEntityReference();
            Opportunity opportunity2 = new Opportunity();
            opportunity2.Name = "TestUpdateAccountValueWorkflow 2 " + DateTime.Now;
            opportunity2.ActualValue = new Money(200000);
            opportunity2.ParentAccountId = account.ToEntityReference();

            opportunity1.Id = this.OrganizationService.Create(opportunity1);
            opportunity2.Id = this.OrganizationService.Create(opportunity2);

            accountOpportunities = new List<Opportunity>(2);
            accountOpportunities.Add(opportunity1);
            accountOpportunities.Add(opportunity2);

            return opportunity2.Id;
        }

        #endregion

        #region Test

        [TestMethod]
        public void RunTestUpdateAccountValueWorkflow()
        {
            base.Test();
        }

        #endregion

        #region Verify

        protected override void VerifyStatus()
        {
            Assert.AreEqual(Status, AsyncStatus.Pass);

            //Verify Account Value
            decimal expectedTotal = this.accountOpportunities.Sum(op => op.ActualValue.Value);
            decimal actualTotal = RetrieveActualAccountValue();
            Assert.AreEqual(expectedTotal, actualTotal);

            //Verify email has been sent since Account is worth more than One Million
            IQueryable<Email> emails = AccountEmails(this.account);
            Assert.IsNotNull(emails);
            Assert.IsTrue(emails.ToList().Count > 0);
            
        }

        private IQueryable<Email> AccountEmails(Account account)
        {
            using (XrmServiceContext xrmContext = new XrmServiceContext(this.OrganizationService))
            {
                var emails = from email in xrmContext.EmailSet
                           where email.RegardingObjectId.Id == account.Id
                           select email;
                return emails;
            }
        }

        private decimal RetrieveActualAccountValue()
        {
            decimal actualTotal = 0M;

            using (XrmServiceContext xrmContext = new XrmServiceContext(this.OrganizationService))
            {
                var opps = from opp in xrmContext.OpportunitySet
                           where opp.AccountId.Id == account.Id
                           select opp.ActualValue;

                foreach (Money actual in opps)
                {
                    actualTotal += actual.Value;
                }
            }

            return actualTotal;
        }

        #endregion

        #region Clean up

        protected override void CleanUp()
        {
            base.CleanUp();

            foreach (Opportunity opp in accountOpportunities)
                this.OrganizationService.Delete(opp.LogicalName, opp.Id);

            this.OrganizationService.Delete(account.LogicalName,account.Id);
            
        }

        #endregion
    }
}
